package com.huawei.hwclouds.lubanops.demo.common.exception;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.huawei.hwclouds.lubanops.demo.common.exception.common.JsonException;
import com.huawei.hwclouds.lubanops.demo.common.exception.common.WrongFormatException;
import com.huawei.hwclouds.lubanops.demo.common.json.JsonUtil;
import com.huawei.hwclouds.lubanops.demo.common.model.ErrorMessage;

/**
 * 这个异常作为apm2的所有的异常的基类
 * apm2的所有错误码的定义,错误码的格式 apm2.xxxxyyyy 其中xxxx四位为微服务编号，yyyy四位为错误编号，其中yyyy，0000 到1000 为系统错误，1001-9999 为业务型错误
 * 这里代表的是微服务为SYS开始的微服务，比如 SYS,SYS_HBASE,SYS_ES等的错误码
 *
 * @author y00438022
 */
public class ErrorCodeException extends RuntimeException {

    private static final Logger LOG = LoggerFactory.getLogger(ErrorCodeException.class);

    private static final long serialVersionUID = 7929100143473336645L;

    private String serviceCode;

    private String errorCode;

    /**
     * 错误码对应的消息，一般是预先定义
     */
    private String msg;

    /**
     * 用户指定的错误消息，比如 throw xxxException（"xxxxxx"）
     */
    private String hint;

    public ErrorCodeException(String service, String code, String msg, String hint) {
        super(toErrorMsg(service, code, msg, hint));
        this.serviceCode = service;
        this.errorCode = code;
        this.msg = msg;
        this.hint = hint; //异常的提示内容
    }

    public ErrorCodeException(String service, String code, String msg, String hint, Throwable e) {
        super(toErrorMsg(service, code, msg, hint), e);
        this.serviceCode = service;
        this.errorCode = code;
        this.msg = msg;
        this.hint = hint; //异常的提示内容
    }

    private static String toErrorMsg(String service, String code, String msg, String hint) {
        StringBuilder sb = new StringBuilder();
        sb.append("apm2.").append(service).append(code);
        sb.append(":").append(msg).append(":").append(hint);
        return sb.toString();
    }

    /**
     * 将下面格式的json字符串转换成ErrorCodeException 对象
     * {
     * "error_code":"apm2.00001000",
     * "error_msg":"xxxxxxxx",
     * "hint":"xxxxxxxxxxxxx"
     * }
     *
     * @param json 输入的json字符串
     * @return ErrorCodeException对象，如果为空，代表输入字符串非json，或者json字符串没有包含error_code元素
     */
    public static ErrorCodeException toErrorCodeException(String json) {
        try {
            ErrorMessage error = JsonUtil.parseObject(json, ErrorMessage.class);
            if (StringUtils.isBlank(error.getErrorCode())) { //如果错误码没有 那就是空
                return null;
            }

            String[] ss = ErrorCodeParser.parseString(error.getErrorCode());
            String serviceName = ss[1];
            String bizError = ss[2];
            return new ErrorCodeException(serviceName, bizError, error.getErrorMsg(), error.getHint());
        } catch (JsonException ex) {
            return new WrongFormatException("result is not a json string:" + json);
        }

    }

    public String getErrorCode() {
        return errorCode;
    }

    public String getMsg() {
        return msg;
    }

    public String getServiceCode() {
        return serviceCode;
    }

    public String getHint() {
        return hint;
    }

    /**
     * 转换成json格式的字符串
     * {
     * "error_code":"apm2.00001000",
     * "error_msg":"xxxxxxxx",
     * "hint":"xxxxxxxxxxxxx"
     * }
     *
     * @return
     */
    public String toJsonString(boolean showHint) {
        ErrorMessage error = new ErrorMessage();
        error.setErrorCode(ErrorCodeParser.toErrorCodeString(this.serviceCode, this.errorCode));
        error.setErrorMsg(this.getMsg());

        if (showHint) {
            error.setHint(this.getHint());
        }

        return JsonUtil.toJSONString(error);
    }

    /**
     * 默认不需要输出hint
     *
     * @return
     */
    public String toJsonString() {
        return toJsonString(false);
    }

    /**
     * 针对安全要求对字符串进行过滤 <br>
     *
     * @param s
     * @return
     * @author y00438022
     */
    public String secureMsg(String s) {
        if (s == null) {
            return "";
        }
        if (s.contains("<")) {
            return "format error";
        } else {
            return s;
        }
    }

}
